package com.antoco.operation.bigscreen.service;

import com.antoco.operation.bigscreen.config.ChannelConfig;
import com.antoco.operation.bigscreen.mapper.SensorMapper;
import com.antoco.operation.bigscreen.mapper.SensorWarnShowMapper;
import com.antoco.operation.bigscreen.model.dto.SensorDTO;
import com.antoco.operation.bigscreen.model.dto.SensorWarnShowDTO;
import com.antoco.operation.bigscreen.model.entity.Sensor;
import com.antoco.operation.bigscreen.model.entity.TjZt;
import com.antoco.operation.bigscreen.repository.TjZtRepository;
import com.antoco.operation.bigscreen.service.autogeneration.impl.SensorServiceImpl;
import com.antoco.operation.bigscreen.service.autogeneration.impl.SensorWarnServiceImpl;
import com.antoco.operation.bigscreen.utils.StringUtil;
import com.antoco.operation.bigscreen.utils.SystemUtil;

import javassist.NotFoundException;
import net.sf.json.JSONArray;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import com.google.common.base.CaseFormat;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.Table;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 频道数据服务类
 * @author johnsonpei
 */
@Service
public class ChannelDataService {

    @Resource
    private ApplicationContext applicationContext;

    @Autowired
    private ChannelConfig channelConfig;

    @Autowired
    private ReflectionService reflectionService;

    @Autowired
    private SystemUtil systemUtil;

    @Autowired
    private SensorWarnServiceImpl sensorWarnServiceImpl;

    @Autowired
    private SensorServiceImpl sensorServiceImpl;

    @Autowired
    private WebSocketServer webSocketServer;

    @Autowired
    private SensorWarnShowMapper sensorWarnShowMapper;

    @Autowired
    private SensorMapper sensorMapper;

    @Autowired
    private TjZtRepository tjZtRepository;

    @Autowired
    private EntityManager entityManager;

    /**
     * 获取频道所有表数据
     *
     * @param channelName
     * @return {
     * "tj_zt" : [
     * {"lastTranEtlTaskId":"24","lastTjInsId":"19","name":"suiwei_watch","tjInsDetailTableName":"suiwei_watch","id":"1"},
     * {"lastTranEtlTaskId":"20","lastTjInsId":"18","name":"show_name","tjInsDetailTableName":"suiwei_watch","id":"2"}
     * ],
     * "tj_ins": [
     * {"lastTranEtlTaskId":"24","lastTjInsId":"19","name":"suiwei_watch","tjInsDetailTableName":"suiwei_watch","id":"1"},
     * {"lastTranEtlTaskId":"20","lastTjInsId":"18","name":"show_name","tjInsDetailTableName":"suiwei_watch","id":"2"}
     * ]
     * }
     */
    public JSONObject getChannelAllData(String channelName) {
        JSONObject resultJson = new JSONObject();
        JSONObject dataDetail = new JSONObject();

        Map<String, String> channelTables = channelConfig.getChannelTables(channelName);
        if (channelTables.size() > 0) {
            for (String tableName : channelTables.keySet()) {
                dataDetail.put(tableName, getTableData(tableName));
            }
        }

        resultJson.put("channel", channelName);
        resultJson.put("data", dataDetail);
        return resultJson;
    }

    /**
     * 获取水质频道和水量频道数据，只有sensor_warn和sensor表的数据需要经过特殊处理
     * @param channelName
     * @param type
     * @return
     */
    public net.sf.json.JSONObject getSuiData(String channelName,String type) {
        net.sf.json.JSONObject resultJson = new net.sf.json.JSONObject();
        net.sf.json.JSONObject dataDetail = new net.sf.json.JSONObject();

        // 获取频道中的所有表
        Map<String, String> channelTables = channelConfig.getChannelTables(channelName);

        if (channelTables.size() > 0) {
            for (String tableName : channelTables.keySet()) {
                // 根据水位/水量判断告警记录
                if(tableName.equals("sensor_warn")){
                    List<SensorWarnShowDTO> list = sensorWarnShowMapper.asDTOList(sensorWarnServiceImpl.queryListByCondition(type));
                    JSONArray jsonArray = JSONArray.fromObject(list);
                    dataDetail.put(tableName,jsonArray);
                }
                // 根据水位/水量判断传感器
                else if(tableName.equals("sensor")){
                    List<Sensor> sensorList = sensorServiceImpl.queryListByCondition(type);
                    JSONArray sensorArray = JSONArray.fromObject(sensorList);
                    dataDetail.put(tableName,sensorArray);
                }
                else{
                    // dataDetail.put(tableName, getTableAllData(tableName));
                    // 只获取最新统计实例的数据
                    dataDetail.put(tableName, getTableData(tableName));
                }
            }
        }

        resultJson.put("channel", channelName);
        resultJson.put("data", dataDetail);
        return resultJson;
    }



    /**
     * 获取SENSO频道的数据，sensor_wan需要经过特殊处理
     * @param channelName
     * @param id
     * @return
     */
    public net.sf.json.JSONObject getSENSOResult(String channelName,String id) {
        net.sf.json.JSONObject resultJson = new net.sf.json.JSONObject();
        net.sf.json.JSONObject dataDetail = new net.sf.json.JSONObject();

        Map<String, String> channelTables = channelConfig.getChannelTables(channelName);
        if (channelTables.size() > 0) {
            for (String tableName : channelTables.keySet()) {
                if(tableName.equals("sensor_warn")){
                    List<SensorWarnShowDTO> list = sensorWarnShowMapper.asDTOList(sensorWarnServiceImpl.queryListBySensorId(id));
                    JSONArray jsonArray = JSONArray.fromObject(list);
                    dataDetail.put(tableName,jsonArray);
                } else if (tableName.equals("sensor")) {
                    List<SensorDTO> list = sensorMapper.asDTOList(sensorServiceImpl.queryListById(Long.valueOf(id)));
                    JSONArray jsonArray = JSONArray.fromObject(list);
                    dataDetail.put(tableName,jsonArray);
                } else {
                    dataDetail.put(tableName, getTableAllData(tableName));
                }
            }
        }

        resultJson.put("channel", channelName.concat("@").concat(id));
        resultJson.put("data", dataDetail);
        return resultJson;
    }

    /**
     * 根据表名获取推送数据
     *
     * @param tableName
     * @return
     */
    public Object getTableAllData(String tableName) {
        Object result = null;

        try {
            // 获取相应的数据
            String className = StringUtil.convertTableName2ClassName(tableName, false);
            String serviceName = className + "ServiceImpl";
            systemUtil.printDebug("tableName:" + tableName);
            systemUtil.printDebug("serviceName:" + serviceName);

            Map<String, Object> paramMap = new ConcurrentHashMap<String, Object>(0);
            result = reflectionService.invokeService(serviceName, "getChangedData", paramMap);
        } catch (Exception e) {
            systemUtil.printfDebug("異常発生:%s", e.getMessage());
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 根据表名获取符合条件的推送数据
     *
     * @param tableName
     * @return
     */
    public Object getTableData(String tableName) {
        Object result = null;
        try {
            // 获取相应的数据
            List<TjZt> tjZts = tjZtRepository.findByTjInsDetailTableName(tableName);
            if (tjZts.size() > 0) {
                TjZt tjZt = tjZts.get(0);
                String lastTjInsId = tjZt.getLastTjInsId();
                if (StringUtils.isNotEmpty(lastTjInsId)) {
                    String modelName = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, tableName);
                    Class<?> modelClass = Class.forName("com.antoco.operation.bigscreen.model.entity." + modelName);
                    StringBuffer sql = new StringBuffer("select * from " + tableName + " where tj_ins_id = :tjInsId");
                    Query query = entityManager.createNativeQuery(sql.toString(), modelClass);
                    query.setParameter("tjInsId" , lastTjInsId);
                    result = query.getResultList();
                }
            }
        } catch (Exception e) {
            systemUtil.printfDebug("異常発生:%s", e.getMessage());
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 根据当前的controller类名获取数据，进行推送数据
     * @param className
     */
    public void pushAllLists(String className) {
        try {
            int strStartIndex = className.lastIndexOf(".");
            int strEndIndex = className.indexOf("ControllerImpl");
            String newclassName = className.substring(strStartIndex+1, strEndIndex);
            Class<?> allclassName = Class.forName("com.antoco.operation.bigscreen.model.entity."+newclassName);
            String tableName = getTableName(allclassName);
            // 获取频道名
            List<String> channelNames = channelConfig.getChannelNameByTableName(tableName);
            if (channelNames.size() == 0) {
                throw new NotFoundException("无法找到表名所对应的频道。表名无效，或者application.properties配置有误！ tableName:" + tableName);
            }
            // 获取相应的数据
            Object result = null;
            List<TjZt> tjZts = tjZtRepository.findByTjInsDetailTableName(tableName);
            if (tjZts.size() > 0) {
                TjZt tjZt = tjZts.get(0);
                String lastTjInsId = tjZt.getLastTjInsId();
                if (StringUtils.isNotEmpty(lastTjInsId)) {
                    String modelName = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, tableName);
                    Class<?> modelClass = Class.forName("com.antoco.operation.bigscreen.model.entity." + modelName);
                    StringBuffer sql = new StringBuffer("select * from " + tableName + " where tj_ins_id = :tjInsId");
                    Query query = entityManager.createNativeQuery(sql.toString(), modelClass);
                    query.setParameter("tjInsId" , lastTjInsId);
                    result = query.getResultList();
                }
            }
            // systemUtil.printDebug("查询结果：" + result.toString());
            // 推送数据给所有websocket客户端
            for (String channelName : channelNames) {
                JSONObject resultJson = new JSONObject();
                resultJson.put("channel", channelName);
                resultJson.put("data", new JSONObject().put(tableName, result));
                webSocketServer.send2Channel(channelName, resultJson.toString());
            }
        } catch (Exception e) {
            systemUtil.printfDebug("发生异常：%s", e.toString());
            if (systemUtil.getDebug()) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 根据类名获取注解的表名称
     * @param clazz
     * @return
     */
    public static String getTableName(Class<?> clazz) {
        Table annotation = clazz.getAnnotation(Table.class);
        String name = annotation.name();
        String className = clazz.getSimpleName();
        return name;
    }
}
